/**
 * upload4j封装渲染组件
 */
jQuery(function() {
	
	//多文件上传渲染
	$.each( $(".4jUploader"), function(i, n){
		analyzeUploadHtml($(n));
	});
	
	$("body").on("mouseover",".upload_thum",function(){
		$(this).find('.imgdel').show();
	}).on("mouseout",".upload_thum",function(){
		$(this).find('.imgdel').hide();
	});
	
	$("body").on("mouseover",".webuploader-pick",function(){
		$(this).find('.imgdel').show();
	}).on("mouseout",".upload_thum",function(){
		$(this).find('.imgdel').hide();
	});
	
	
});

/**
 * upload4j解析类
 * 图片或文件设置的初始大小是3M和10M，如果超过了本机的php.ini配置文件里的大小就会上传失败，图片或文件无法显示。则需要设置php.ini,参考文章http://wangking717.iteye.com/blog/1947080
 * @param $this 对象obj本身
 */
function analyzeUploadHtml($this){

	if($this == null){
		alert("upload4j解析出错！");
		return;
	}
	
	var width4container = $this.width();	//容器宽度，用来设置文件重命名时，输入框的大小，不然会错位。
	var id = $this.attr("cname");
	var hiddenName = $this.attr('hidden_name') == '' ? id:$this.attr('hidden_name');
	var moreHiddenName = $this.attr('more_hidden_name');
	var type = $this.attr("type");
	var value = $this.attr("value");
	var extType = $this.attr("ext");
	var asset_path = $this.attr("asset_path");
	var width = $this.attr("width");
    var height = $this.attr("height");
    
    
	var itemHtmlVal = "";
	var fileList = new Array();
	var isMulti = false;
	var fileSize4baidu = 10 * 1024 * 1024;	//默认为图片大小(10MB)，供百度webuploader使用
	var fileExts = $this.attr("ext") == 'img'? "*.gif;*.jpg;*.jpeg;*.png":"*.*";
	var inputclass = width4container <= 500? "ipt small-ipt":"ipt";
	if(type == 'multi'){	//【多文件、图片】文件上传
		fileList = value.split("[]");
		isMulti = true;
	}else{	//【单文件、图片】上传
		fileList[0] = value;
	}
	
	if(extType == 'file'){	//file upload
		
		for(var i=0;i<fileList.length;++i){
			if(fileList[i] != ""){
				var obj = fileList[i].split(":");
				var fileExt = "";
				var ext = getExtname(obj[0]);
				if(ext != ""){
					fileExt = '<a href="javascript:;" class="file_ext">'+ext+'</a>&nbsp;&nbsp;&nbsp;';
				}
				var uploadID = hex_md5(fileList[i]);
				itemHtmlVal += '<div class="upload_file clearfix" id="'+uploadID+'">'+
						'<div class="fl">'+
							'<a href="'+obj[0]+'" class="display_name_tag" target="_blank">'+obj[1]+ext+'</a>'+
							'<div class="input_name_tag">'+
								'<input type="text" id="'+uploadID+'_text" value="'+obj[1]+'" class="'+inputclass+'" />&nbsp;'+fileExt+
								'<a class="btn btn-info" href="javascript:saveFileName(\''+uploadID+'\',\''+id+'\',\''+obj[0]+'\',\''+ext+'\');">保存</a>&nbsp;'+
								'<a class="btn" href="javascript:cancelSetRename(\''+uploadID+'\');">取消</a>'+
							'</div>'+
						'</div>'+
						'<div class="fr">'+
							'<a href="javascript:setRename(\''+uploadID+'\');" class="file_func">重命名</a>&nbsp;&nbsp;&nbsp;&nbsp;'+
							'<span class="del_tag"><a href="javascript:deleteUploadFile(\''+uploadID+'\',\''+id+'\',\''+obj[0]+'\',\''+obj[1]+'\',\'\');" class="file_func">删除</a></span>'+
						'</div>'+
					'</div>';
			}
		}
		
	}else{	//image upload
		
		var fileactiontype = '';
		if(isMulti == false){
			fileactiontype = 'singelIMG';
		}
		
		for (var i = 0; i < fileList.length; ++i) {
			if (fileList[i] != "") {
				var uploadID = hex_md5(fileList[i]);
				itemHtmlVal += '<span class="upload_thum" id="'+uploadID+'">'+
						'<img src="'+fileList[i]+'" width="100" height="100" />'+
						'<a href="javascript:deleteUploadFile(\''+uploadID+'\',\''+id+'\',\''+fileList[i]+'\',\'\',\''+fileactiontype+'\');" class="imgdel">删</a>'+
					'</span>';
			}
		}
		
	}
	
	var buttonText = "";
	if(isMulti == true){
		if(extType == "file"){
			buttonText = "多文件上传...";
		}else{
			//buttonText = "多图片上传...";
			buttonText = '<img src="'+asset_path+'/add.png" />';
		}
	}else{
		if(extType == "file"){
			buttonText = "单文件上传...";
		}else{
			//buttonText = "单图片上传...";
			buttonText = '<img src="'+asset_path+'/add.png" />';
		}
	}
	
	var moreHiddenStr = '';	//提供一个附加的隐藏域，供PHP灵活控制，一般在于一个页面用到该多个相同model动态JS增加，一次性提交的时候，需要控制
	if(moreHiddenName != ''){
		moreHiddenStr = '<input type="hidden" name="'+moreHiddenName+'" value="'+value+'" />';
	}
	
	var htmlVal = '';
	if(extType == "file"){
		
		var actionType = 'multi_file[]';
		if(isMulti == false){
			actionType = 'single_file[]';
		}
		
		htmlVal = '<div class="multi_uploader">'+
							'<input type="hidden" id="'+id+'_text" name="'+hiddenName+'" value="'+value+'" />'+
							moreHiddenStr+
							'<input type="hidden" name="'+id+'_width" value="'+width+'" />'+
							'<input type="hidden" name="'+id+'_height" value="'+height+'" />'+
							'<input type="hidden" name="'+actionType+'" value="'+id+'" />'+
							'<div class="head clearfix">'+
								'<div id="'+id+'" style="float:left;">'+buttonText+'</div>'+
								'<span id="'+id+'_progress" class="uploader_process"></span>'+
							'</div>'+
							'<div id="'+id+'_filelist" class="filelist">'+itemHtmlVal+'</div>'+
						'</div>';
	}else{
		
		if(isMulti == false){	//单图上传
			
			if(itemHtmlVal != ''){	//有上传图
				buttonText = '<img src="'+fileList[0]+'" />';	//替换成实际上传了的图
				buttonText += '<a href="javascript:deleteSingelImg(\''+uploadID+'\',\''+id+'\',\''+fileList[0]+'\',\''+asset_path+'\');" class="imgdel">删</a>';
			}
			htmlVal = '<div class="multi_uploader">'+
							'<input type="hidden" id="'+id+'_text" name="'+hiddenName+'" value="'+value+'" />'+
							moreHiddenStr+
							'<input type="hidden" name="'+id+'_width" value="'+width+'" />'+
							'<input type="hidden" name="'+id+'_height" value="'+height+'" />'+
							'<input type="hidden" name="single_img[]" value="'+id+'" />'+
							'<div id="'+id+'_filelist" class="filelist imglist">'+
								'<span id="'+id+'" class="upload_thum">'+
									buttonText+
									'<span id="'+id+'_progress" class="uploader_process img_process"></span>'+
								'</span>'+
							'</div>'+
						'</div>';
			
		}else{
			htmlVal = '<div class="multi_uploader">'+
							'<input type="hidden" id="'+id+'_text" name="'+hiddenName+'" value="'+value+'" />'+
							moreHiddenStr+
							'<input type="hidden" name="'+id+'_width" value="'+width+'" />'+
							'<input type="hidden" name="'+id+'_height" value="'+height+'" />'+
							'<input type="hidden" name="multi_img[]" value="'+id+'" />'+
							'<div id="'+id+'_filelist" class="filelist imglist">'+
								'<span class="img_block">'+
									itemHtmlVal+
								'</span>'+
								'<span id="'+id+'" class="upload_thum">'+
									buttonText+
									'<span id="'+id+'_progress" class="uploader_process img_process"></span>'+
								'</span>'+
							'</div>'+
						'</div>';
		}
		
	}
	$this.html(htmlVal);
	callWebuploader(id,extType,isMulti,fileSize4baidu,$this.attr("timestamp"),$this.attr("salt"),asset_path,width4container);
	
}

/**
 * 调用webuploader
 * @param id	要渲染的upload组建
 * @param extType	后缀限制，文件上传“file”、图片上传“img”
 * @param fileSize 图片大小3MB，文件大小10MB，对应php.ini服务端定义上传限制为10MB，参考http://www.jb51.net/article/18975.htm
 */
function callWebuploader(id, extType,isMulti,fileSize,timestamp,token,ASSET_PATH,width4container) {
	
	var acceptVal = null;
	var percentages = {};
	var total = 0;	//总共的文件数，供进度条使用
	if(extType == 'img'){
		//acceptVal = {title: 'Images',extensions: 'gif,jpg,jpeg,bmp,png',mimeTypes: 'image/*'};	//mimeTypes: 'image/*'方式在chrome52.0.2743.80以上 存在BUG，反应很慢。
		acceptVal = {title: 'Images',extensions: 'gif,jpg,jpeg,bmp,png',mimeTypes: 'image/jpg,image/jpeg,image/png,image/gif,image/bmp'};
	}
	var fileNumLimitVal;
	if(isMulti == false){
		fileNumLimitVal = 1;
	}
	
	var uploader = WebUploader.create({
        auto:true,
        accept:acceptVal,
        swf:ASSET_PATH+'/webuploader.swf',
        server:ASSET_PATH+"/webuploader.php",
        pick:'#'+id,
        fileNumLimit:fileNumLimitVal,
        fileSingleSizeLimit:fileSize,
        formData: {
        	'extType' : extType,
            'timestamp': timestamp,
            'token': token
        }
    });
	
	// 当文件被加入队列之前触发，此事件的handler返回值为false，则此文件不会被添加进入队列。
    uploader.on('beforeFileQueued', function(file){
		if(file.ext == 'php'){	//过滤php文件，方式被提权
    		return false;
    	}
    });
	
	// 当有文件添加进来的时候
    uploader.on('fileQueued', function(file){
    	total++;
    	if(extType == 'img'){
			var $process = $("#"+id+"_progress");
    		$process.parent().find('img').attr('src',ASSET_PATH+'/blank.png');
    		$process.html('<span style="color:gray;">加载中</span>');
    		
    	}else{
    		$("#"+id+"_progress").html('<span style="color:gray;">文件上传中...</span>');
    	}
    	
    });
	
    //文件上传过程中创建进度条实时显示。
    uploader.on('uploadProgress', function(file, percentage) {
        
    	var loaded = 0,percent;
    	percentages[file.id] = percentage;
    	
    	$.each(percentages, function(k,v) {
           loaded += v;
        });
    	
    	percent = Math.round((loaded / total) * 100);
    	if(percent == 100){
    		$("#"+id+"_progress").html('<span style="color:green;">'+percent + '%</span>');
    	}else{
    		$("#"+id+"_progress").html('<span style="color:blue;">'+percent + '%</span>');
    	}
    	
    });
	
	//文件上传成功，给item添加成功class, 用样式标记上传成功。
    uploader.on('uploadSuccess', function(file,result){
    	
        if (result.status == 0) {
            alert(result.msg);
            return;
        }
		
		//以下则为成功上传流程
    	var htmlVal = '';
    	var uploadID = hex_md5(result.msg);
    	if(extType == 'file'){	//multi file upload
    		var obj = result.msg.split(":");
    		var filename = getFilename(obj[1]);
    		if(filename == ''){
    			alert("“"+obj[1]+"”，该文件没有名称，操作失败。")
    			return;
    		}
			var fileExt = "";
			var ext = getExtname(obj[1]);
			var inputclass = width4container <= 500? "ipt small-ipt":"ipt";
			if(ext != ""){
				fileExt = '<a href="javascript:;" class="file_ext">'+ext+'</a>&nbsp;&nbsp;&nbsp;';
			}
    		htmlVal = '<div class="upload_file clearfix" id="'+uploadID+'">'+
    						'<div class="fl">'+
								'<a href="'+obj[0]+'" class="display_name_tag" target="_blank">'+obj[1]+'</a>'+
								'<div class="input_name_tag">'+
									'<input type="text" id="'+uploadID+'_text" value="'+filename+'" class="'+inputclass+'" />&nbsp;'+fileExt+
									'<a class="btn btn-info" href="javascript:saveFileName(\''+uploadID+'\',\''+id+'\',\''+obj[0]+'\',\''+ext+'\');">保存</a>&nbsp;'+
									'<a class="btn" href="javascript:cancelSetRename(\''+uploadID+'\');">取消</a>'+
								'</div>'+
							'</div>'+
    						'<div class="fr">'+
								'<a href="javascript:setRename(\''+uploadID+'\');" class="file_func">重命名</a>&nbsp;&nbsp;&nbsp;&nbsp;'+
								'<span class="del_tag"><a href="javascript:deleteUploadFile(\''+uploadID+'\',\''+id+'\',\''+obj[0]+'\',\''+obj[1]+'\',\'\');" class="file_func">删除</a></span>'+
							'</div>'+
    					'</div>';
    	}else{	//multi image upload
    		
    		var fileactiontype = '';
    		if(isMulti == false){
    			fileactiontype = 'singelIMG';
    		}
    		
    		htmlVal = '<span class="upload_thum" id="'+uploadID+'">'+
    						'<img src="'+result.msg+'" width="100" height="100" />'+
    						'<a href="javascript:deleteUploadFile(\''+uploadID+'\',\''+id+'\',\''+result.msg+'\',\'\',\''+fileactiontype+'\');" class="imgdel">删</a>'+
    					'</span>';
    	}
		
		if(isMulti == true){
			if(extType == 'file'){	//file upload
				$("#"+id+"_filelist").append(htmlVal);
			}else{
				$("#"+id+"_filelist .img_block").append(htmlVal);
			}
			var $inputText = $("#"+id+"_text");
			var val = $inputText.val();
			if($inputText.val() != ''){
				val += "[]";
			}
			if(extType == 'file'){	//file upload
				$inputText.val(val+getFilename(result.msg));
			}else{
				$inputText.val(val+result.msg);
			}
			
		}else{
			if(extType == 'file'){	//file upload
				$("#"+id+"_filelist").html(htmlVal);
			}else{
				var delStr = '<a href="javascript:deleteSingelImg(\''+uploadID+'\',\''+id+'\',\''+result.msg+'\',\''+ASSET_PATH+'\');" class="imgdel">删</a>';
				$("#"+id).find('.webuploader-pick').append(delStr);
				$("#"+id).find('img').attr('src',result.msg);
			}
			var $inputText = $("#"+id+"_text");
			if(extType == 'file'){	//file upload
				$inputText.val(getFilename(result.msg));
			}else{
				$inputText.val(result.msg);
			}
			
		}
		if(extType == 'img'){
			var $progress = $("#"+id+"_progress");
			$progress.html('');
			if(isMulti == true){
				$progress.parent().find('img').attr('src',ASSET_PATH+'/add.png');
			}
		}
		uploader.removeFile(file);	//移除队列
		
		
    });
    
	
}

/**
 * 设置文件重命名
 */
function setRename(uploadID){
	var $this = $("#"+uploadID);
	$this.find(".input_name_tag").show();
	$this.find(".display_name_tag").hide();
}

/**
 * 取消设置文件重命名
 */
function cancelSetRename(uploadID){
	var $this = $("#"+uploadID);
	$this.find(".input_name_tag").hide();
	$this.find(".display_name_tag").show();
}

/**
 * 文件上传模块：重命名对其保存的函数
 */
function saveFileName(uploadID,id,filename,ext){
	//<span class="del_tag">
	var $this = $("#"+uploadID);
	var $inputText = $("#"+id+"_text");
	var $display_name_tag = $this.find(".display_name_tag");
	var $del_tag = $this.find(".del_tag");
	
	var oldval = getFilename($display_name_tag.html());	//原始的文件名称
	var newval = $("#"+uploadID+"_text").val();	//新输入的文件名称
	
	if(newval.indexOf('<') > 0 || newval.indexOf('>') > 0 || newval.indexOf('/') > 0 || newval.indexOf(':') > 0 || newval.indexOf('*') > 0 || newval.indexOf('?') > 0 || newval.indexOf('"') > 0 || newval.indexOf("\\") > 0){
		alert('不能包含非法字符！');
		return false;
	}
	if(newval == ''){
		alert('请输入文件名！');
		return false;
	}
	
	var oldMatchStr = filename+':'+oldval;
	var newMatchStr = filename+':'+newval;
	var delStr = $del_tag.html();
	delStr = delStr.replace(oldval,newval);
	
	//替换HIDDEN存入的数据
	var inputval = $inputText.val();
	inputval = inputval.replace(oldMatchStr,newMatchStr);
	$inputText.val(inputval);
	//将文本替换成新的内容，并且进行隐藏输入框，显示新内容事件处理
	$display_name_tag.html(newval+ext);
	$del_tag.html(delStr);
	$this.find(".input_name_tag").hide();
	$this.find(".display_name_tag").show();
	
}

/**
 * deleteUploadFile文件删除
 */
function deleteUploadFile(uploadID,id,fileaddr,filename,filetype){
	var $inputText = $("#"+id+"_text");
	$("#"+uploadID).remove();
	var val = $inputText.val();
	
	var fileVal = fileaddr;
	if(filename != ''){
		fileVal = fileaddr+':'+filename;
	}
	
	if(filetype == 'singelIMG'){	//如果是单图片上传方式，操作流程不一样
		$("#"+id).show();
	}
	
	
	//双重替换关键字
	val = val.replace('[]'+fileVal,'');
	val = val.replace(fileVal,'');
	$inputText.val(val);
}

/**
 * 删除单图上传的图片
 */
function deleteSingelImg(uploadID,id,fileaddr,ASSET_PATH){
	var $obj = $("#"+id);
	var $inputText = $("#"+id+"_text");
	$("#"+uploadID).remove();
	var val = $inputText.val();
	
	var fileVal = fileaddr;
	$obj.find('.webuploader-pick .imgdel').remove();
	$obj.find('.webuploader-pick img').attr('src',ASSET_PATH+'/add.png');
	$obj.show();
	
	//双重替换关键字
	val = val.replace('[]'+fileVal,'');
	val = val.replace(fileVal,'');
	$inputText.val(val);
}

//获取文件名
function getFilename(val){
	arr = new Array();
	arr = val.split(".");
	var filename = "";
	for (var i=0;i<arr.length-1;i++){
		if(i != 0){
			filename += '.';
		}
		filename += arr[i];
	}
	return filename;
}

//获取文件后缀名
function getExtname(val){
	arr = new Array();
	arr = val.split(".");
	extname = arr[arr.length - 1];
	return "."+extname;
}

/*
 * MD加密插件
 * See http://pajhome.org.uk/crypt/md5 for more info.
 */

var hexcase = 0;  /* hex output format. 0 - lowercase; 1 - uppercase        */
var b64pad  = ""; /* base-64 pad character. "=" for strict RFC compliance   */
var chrsz   = 8;  /* bits per input character. 8 - ASCII; 16 - Unicode      */

/*
 * These are the functions you'll usually want to call
 * They take string arguments and return either hex or base-64 encoded strings
 */
function hex_md5(s){ return binl2hex(core_md5(str2binl(s), s.length * chrsz));}
function b64_md5(s){ return binl2b64(core_md5(str2binl(s), s.length * chrsz));}
function str_md5(s){ return binl2str(core_md5(str2binl(s), s.length * chrsz));}
function hex_hmac_md5(key, data) { return binl2hex(core_hmac_md5(key, data)); }
function b64_hmac_md5(key, data) { return binl2b64(core_hmac_md5(key, data)); }
function str_hmac_md5(key, data) { return binl2str(core_hmac_md5(key, data)); }

/*
 * Perform a simple self-test to see if the VM is working
 */
function md5_vm_test()
{
  return hex_md5("abc") == "900150983cd24fb0d6963f7d28e17f72";
}

/*
 * Calculate the MD5 of an array of little-endian words, and a bit length
 */
function core_md5(x, len)
{
  /* append padding */
  x[len >> 5] |= 0x80 << ((len) % 32);
  x[(((len + 64) >>> 9) << 4) + 14] = len;

  var a =  1732584193;
  var b = -271733879;
  var c = -1732584194;
  var d =  271733878;

  for(var i = 0; i < x.length; i += 16)
  {
    var olda = a;
    var oldb = b;
    var oldc = c;
    var oldd = d;

    a = md5_ff(a, b, c, d, x[i+ 0], 7 , -680876936);
    d = md5_ff(d, a, b, c, x[i+ 1], 12, -389564586);
    c = md5_ff(c, d, a, b, x[i+ 2], 17,  606105819);
    b = md5_ff(b, c, d, a, x[i+ 3], 22, -1044525330);
    a = md5_ff(a, b, c, d, x[i+ 4], 7 , -176418897);
    d = md5_ff(d, a, b, c, x[i+ 5], 12,  1200080426);
    c = md5_ff(c, d, a, b, x[i+ 6], 17, -1473231341);
    b = md5_ff(b, c, d, a, x[i+ 7], 22, -45705983);
    a = md5_ff(a, b, c, d, x[i+ 8], 7 ,  1770035416);
    d = md5_ff(d, a, b, c, x[i+ 9], 12, -1958414417);
    c = md5_ff(c, d, a, b, x[i+10], 17, -42063);
    b = md5_ff(b, c, d, a, x[i+11], 22, -1990404162);
    a = md5_ff(a, b, c, d, x[i+12], 7 ,  1804603682);
    d = md5_ff(d, a, b, c, x[i+13], 12, -40341101);
    c = md5_ff(c, d, a, b, x[i+14], 17, -1502002290);
    b = md5_ff(b, c, d, a, x[i+15], 22,  1236535329);

    a = md5_gg(a, b, c, d, x[i+ 1], 5 , -165796510);
    d = md5_gg(d, a, b, c, x[i+ 6], 9 , -1069501632);
    c = md5_gg(c, d, a, b, x[i+11], 14,  643717713);
    b = md5_gg(b, c, d, a, x[i+ 0], 20, -373897302);
    a = md5_gg(a, b, c, d, x[i+ 5], 5 , -701558691);
    d = md5_gg(d, a, b, c, x[i+10], 9 ,  38016083);
    c = md5_gg(c, d, a, b, x[i+15], 14, -660478335);
    b = md5_gg(b, c, d, a, x[i+ 4], 20, -405537848);
    a = md5_gg(a, b, c, d, x[i+ 9], 5 ,  568446438);
    d = md5_gg(d, a, b, c, x[i+14], 9 , -1019803690);
    c = md5_gg(c, d, a, b, x[i+ 3], 14, -187363961);
    b = md5_gg(b, c, d, a, x[i+ 8], 20,  1163531501);
    a = md5_gg(a, b, c, d, x[i+13], 5 , -1444681467);
    d = md5_gg(d, a, b, c, x[i+ 2], 9 , -51403784);
    c = md5_gg(c, d, a, b, x[i+ 7], 14,  1735328473);
    b = md5_gg(b, c, d, a, x[i+12], 20, -1926607734);

    a = md5_hh(a, b, c, d, x[i+ 5], 4 , -378558);
    d = md5_hh(d, a, b, c, x[i+ 8], 11, -2022574463);
    c = md5_hh(c, d, a, b, x[i+11], 16,  1839030562);
    b = md5_hh(b, c, d, a, x[i+14], 23, -35309556);
    a = md5_hh(a, b, c, d, x[i+ 1], 4 , -1530992060);
    d = md5_hh(d, a, b, c, x[i+ 4], 11,  1272893353);
    c = md5_hh(c, d, a, b, x[i+ 7], 16, -155497632);
    b = md5_hh(b, c, d, a, x[i+10], 23, -1094730640);
    a = md5_hh(a, b, c, d, x[i+13], 4 ,  681279174);
    d = md5_hh(d, a, b, c, x[i+ 0], 11, -358537222);
    c = md5_hh(c, d, a, b, x[i+ 3], 16, -722521979);
    b = md5_hh(b, c, d, a, x[i+ 6], 23,  76029189);
    a = md5_hh(a, b, c, d, x[i+ 9], 4 , -640364487);
    d = md5_hh(d, a, b, c, x[i+12], 11, -421815835);
    c = md5_hh(c, d, a, b, x[i+15], 16,  530742520);
    b = md5_hh(b, c, d, a, x[i+ 2], 23, -995338651);

    a = md5_ii(a, b, c, d, x[i+ 0], 6 , -198630844);
    d = md5_ii(d, a, b, c, x[i+ 7], 10,  1126891415);
    c = md5_ii(c, d, a, b, x[i+14], 15, -1416354905);
    b = md5_ii(b, c, d, a, x[i+ 5], 21, -57434055);
    a = md5_ii(a, b, c, d, x[i+12], 6 ,  1700485571);
    d = md5_ii(d, a, b, c, x[i+ 3], 10, -1894986606);
    c = md5_ii(c, d, a, b, x[i+10], 15, -1051523);
    b = md5_ii(b, c, d, a, x[i+ 1], 21, -2054922799);
    a = md5_ii(a, b, c, d, x[i+ 8], 6 ,  1873313359);
    d = md5_ii(d, a, b, c, x[i+15], 10, -30611744);
    c = md5_ii(c, d, a, b, x[i+ 6], 15, -1560198380);
    b = md5_ii(b, c, d, a, x[i+13], 21,  1309151649);
    a = md5_ii(a, b, c, d, x[i+ 4], 6 , -145523070);
    d = md5_ii(d, a, b, c, x[i+11], 10, -1120210379);
    c = md5_ii(c, d, a, b, x[i+ 2], 15,  718787259);
    b = md5_ii(b, c, d, a, x[i+ 9], 21, -343485551);

    a = safe_add(a, olda);
    b = safe_add(b, oldb);
    c = safe_add(c, oldc);
    d = safe_add(d, oldd);
  }
  return Array(a, b, c, d);

}

/*
 * These functions implement the four basic operations the algorithm uses.
 */
function md5_cmn(q, a, b, x, s, t)
{
  return safe_add(bit_rol(safe_add(safe_add(a, q), safe_add(x, t)), s),b);
}
function md5_ff(a, b, c, d, x, s, t)
{
  return md5_cmn((b & c) | ((~b) & d), a, b, x, s, t);
}
function md5_gg(a, b, c, d, x, s, t)
{
  return md5_cmn((b & d) | (c & (~d)), a, b, x, s, t);
}
function md5_hh(a, b, c, d, x, s, t)
{
  return md5_cmn(b ^ c ^ d, a, b, x, s, t);
}
function md5_ii(a, b, c, d, x, s, t)
{
  return md5_cmn(c ^ (b | (~d)), a, b, x, s, t);
}

/*
 * Calculate the HMAC-MD5, of a key and some data
 */
function core_hmac_md5(key, data)
{
  var bkey = str2binl(key);
  if(bkey.length > 16) bkey = core_md5(bkey, key.length * chrsz);

  var ipad = Array(16), opad = Array(16);
  for(var i = 0; i < 16; i++)
  {
    ipad[i] = bkey[i] ^ 0x36363636;
    opad[i] = bkey[i] ^ 0x5C5C5C5C;
  }

  var hash = core_md5(ipad.concat(str2binl(data)), 512 + data.length * chrsz);
  return core_md5(opad.concat(hash), 512 + 128);
}

/*
 * Add integers, wrapping at 2^32. This uses 16-bit operations internally
 * to work around bugs in some JS interpreters.
 */
function safe_add(x, y)
{
  var lsw = (x & 0xFFFF) + (y & 0xFFFF);
  var msw = (x >> 16) + (y >> 16) + (lsw >> 16);
  return (msw << 16) | (lsw & 0xFFFF);
}

/*
 * Bitwise rotate a 32-bit number to the left.
 */
function bit_rol(num, cnt)
{
  return (num << cnt) | (num >>> (32 - cnt));
}

/*
 * Convert a string to an array of little-endian words
 * If chrsz is ASCII, characters >255 have their hi-byte silently ignored.
 */
function str2binl(str)
{
  var bin = Array();
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < str.length * chrsz; i += chrsz)
    bin[i>>5] |= (str.charCodeAt(i / chrsz) & mask) << (i%32);
  return bin;
}

/*
 * Convert an array of little-endian words to a string
 */
function binl2str(bin)
{
  var str = "";
  var mask = (1 << chrsz) - 1;
  for(var i = 0; i < bin.length * 32; i += chrsz)
    str += String.fromCharCode((bin[i>>5] >>> (i % 32)) & mask);
  return str;
}

/*
 * Convert an array of little-endian words to a hex string.
 */
function binl2hex(binarray){
  var hex_tab = hexcase ? "0123456789ABCDEF" : "0123456789abcdef";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i++)
  {
    str += hex_tab.charAt((binarray[i>>2] >> ((i%4)*8+4)) & 0xF) +
           hex_tab.charAt((binarray[i>>2] >> ((i%4)*8  )) & 0xF);
  }
  return str;
}

/*
 * Convert an array of little-endian words to a base-64 string
 */
function binl2b64(binarray){
  var tab = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/";
  var str = "";
  for(var i = 0; i < binarray.length * 4; i += 3)
  {
    var triplet = (((binarray[i   >> 2] >> 8 * ( i   %4)) & 0xFF) << 16)
                | (((binarray[i+1 >> 2] >> 8 * ((i+1)%4)) & 0xFF) << 8 )
                |  ((binarray[i+2 >> 2] >> 8 * ((i+2)%4)) & 0xFF);
    for(var j = 0; j < 4; j++)
    {
      if(i * 8 + j * 6 > binarray.length * 32) str += b64pad;
      else str += tab.charAt((triplet >> 6*(3-j)) & 0x3F);
    }
  }
  return str;
}

//MD5插件结束